/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.support;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
 * root bean definition 表示合并的bean definition,在运行时支持Spring BeanFactory中的特定bean。
 * 由相互继承的多个原始bean definitions 创建，通常注册为{@link GenericBeanDefinition GenericBeanDefinitions}。
 * A root bean definition 本质上是运行时的“统一” bean  definition 视图。
 * <p>
 * Root bean definitions 也可能用来注册个别 bean definitions 在配置阶段。
 * 但是，从Spring 2.5开始，以编程方式注册Bean definitions 的首选方法是{@link GenericBeanDefinition}。
 * GenericBeanDefinition的优势在于，它允许动态定义父依赖项，而不是将角色“硬编码”为root bean definition。
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see GenericBeanDefinition
 * @see ChildBeanDefinition
 */
@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {

	@Nullable
	private BeanDefinitionHolder decoratedDefinition;

	@Nullable
	private AnnotatedElement qualifiedElement;

	/**
	 * 决定definition 是否需要重新合并
	 */
	volatile boolean stale;

	//允许缓存
	boolean allowCaching = true;

	boolean isFactoryMethodUnique = false;

	@Nullable
	volatile ResolvableType targetType;

	/**
	 * 用于缓存给定bean definition的确定的Class。
	 */
	@Nullable
	volatile Class<?> resolvedTargetType;

	/**
	 * bean是factory bean
	 */
	@Nullable
	volatile Boolean isFactoryBean;

	/**
	 * 缓存通用类型的工厂方法的返回类型。
	 */
	@Nullable
	volatile ResolvableType factoryMethodReturnType;

	/**
	 * 缓存用于自省的唯一工厂方法候选。
	 */
	@Nullable
	volatile Method factoryMethodToIntrospect;

	/**
	 * 以下四个构造函数字段的通用锁。
	 */
	final Object constructorArgumentLock = new Object();

	/**
	 * 缓存已解析的构造函数或工厂方法。
	 */
	@Nullable
	Executable resolvedConstructorOrFactoryMethod;

	/**
	 * 将构造函数参数标记为已解析。
	 */
	boolean constructorArgumentsResolved = false;

	/**
	 * 缓存完全解析的构造函数参数。
	 */
	@Nullable
	Object[] resolvedConstructorArguments;

	/**
	 * 缓存部分准备好的构造函数参数。
	 */
	@Nullable
	Object[] preparedConstructorArguments;

	/**
	 * 以下两个后处理字段的通用锁。
	 */
	final Object postProcessingLock = new Object();

	/**
	 * 表明 MergedBeanDefinitionPostProcessor已应用
	 */
	boolean postProcessed = false;

	/**
	 * 表示实例化之前的后处理器已启动。
	 */
	@Nullable
	volatile Boolean beforeInstantiationResolved;

	/**
	 * TODO： 外部管理的配置 Member
	 */
	@Nullable
	private Set<Member> externallyManagedConfigMembers;

	@Nullable
	private Set<String> externallyManagedInitMethods;

	@Nullable
	private Set<String> externallyManagedDestroyMethods;


	/**
	 * 创建一个新的RootBeanDefinition，通过其bean属性和配置方法进行配置。
	 *
	 * @see #setBeanClass
	 * @see #setScope
	 * @see #setConstructorArgumentValues
	 * @see #setPropertyValues
	 */
	public RootBeanDefinition( ) {
		super();
	}

	/**
	 * 为单例创建一个新的RootBeanDefinition。
	 *
	 * @param beanClass 实例化的bean的类
	 * @see #setBeanClass
	 */
	public RootBeanDefinition(@Nullable Class<?> beanClass) {
		super();
		setBeanClass(beanClass);
	}

	/**
	 * Create a new RootBeanDefinition for a singleton bean, constructing each instance
	 * through calling the given supplier (possibly a lambda or method reference).
	 *
	 * @param beanClass        需要去实例化的bean的类
	 * @param instanceSupplier Supplier去构造一个bean实例，作为声明性指定的工厂方法的替代方法
	 * @see #setInstanceSupplier
	 * @since 5.0
	 */
	public <T> RootBeanDefinition(@Nullable Class<T> beanClass, @Nullable Supplier<T> instanceSupplier) {
		super();
		setBeanClass(beanClass);
		setInstanceSupplier(instanceSupplier);
	}

	/**
	 * Create a new RootBeanDefinition for a scoped bean, constructing each instance
	 * through calling the given supplier (possibly a lambda or method reference).
	 *
	 * @param beanClass        the class of the bean to instantiate
	 * @param scope            指定scope
	 * @param instanceSupplier the supplier to construct a bean instance,
	 *                         as an alternative to a declaratively specified factory method
	 * @see #setInstanceSupplier
	 * @since 5.0
	 */
	public <T> RootBeanDefinition(@Nullable Class<T> beanClass, String scope, @Nullable Supplier<T> instanceSupplier) {
		super();
		setBeanClass(beanClass);
		setScope(scope);
		setInstanceSupplier(instanceSupplier);
	}

	/**
	 * Create a new RootBeanDefinition for a singleton,
	 * using the given autowire mode.
	 *
	 * @param beanClass       the class of the bean to instantiate
	 * @param autowireMode    指定自动装配的类型,是 by name 还是 by type
	 * @param dependencyCheck 是否对对象执行依赖检查（不适用于自动装配构造函数，因此在此处被忽略）
	 */
	public RootBeanDefinition(@Nullable Class<?> beanClass, int autowireMode, boolean dependencyCheck) {
		super();
		setBeanClass(beanClass);
		setAutowireMode(autowireMode);

		if (dependencyCheck && getResolvedAutowireMode() != AUTOWIRE_CONSTRUCTOR) {
			setDependencyCheck(DEPENDENCY_CHECK_OBJECTS);
		}
	}

	/**
	 * Create a new RootBeanDefinition for a singleton,
	 * providing constructor arguments and property values.
	 *
	 * @param beanClass the class of the bean to instantiate
	 * @param cargs     构造器参数
	 * @param pvs       属性值
	 */
	public RootBeanDefinition(@Nullable Class<?> beanClass, @Nullable ConstructorArgumentValues cargs,
							  @Nullable MutablePropertyValues pvs) {

		super(cargs, pvs);
		setBeanClass(beanClass);
	}

	/**
	 * Create a new RootBeanDefinition for a singleton,
	 * providing constructor arguments and property values.
	 * <p>Takes a bean class name to avoid eager loading of the bean class.
	 *
	 * @param beanClassName the name of the class to instantiate
	 */
	public RootBeanDefinition(String beanClassName) {
		setBeanClassName(beanClassName);
	}

	/**
	 * Create a new RootBeanDefinition for a singleton,
	 * providing constructor arguments and property values.
	 * <p>Takes a bean class name to avoid eager loading of the bean class.
	 *
	 * @param beanClassName the name of the class to instantiate
	 * @param cargs         the constructor argument values to apply
	 * @param pvs           the property values to apply
	 */
	public RootBeanDefinition(String beanClassName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
		super(cargs, pvs);
		setBeanClassName(beanClassName);
	}

	/**
	 * 创建一个新的RootBeanDefinition作为给定bean definition的深层副本。
	 *
	 * @param original the original bean definition to copy from
	 */
	public RootBeanDefinition(RootBeanDefinition original) {
		super(original);
		this.decoratedDefinition = original.decoratedDefinition;
		this.qualifiedElement = original.qualifiedElement;
		this.allowCaching = original.allowCaching;
		this.isFactoryMethodUnique = original.isFactoryMethodUnique;
		this.targetType = original.targetType;
		this.factoryMethodToIntrospect = original.factoryMethodToIntrospect;
	}

	/**
	 * Create a new RootBeanDefinition as deep copy of the given
	 * bean definition.
	 *
	 * @param original the original bean definition to copy from
	 */
	RootBeanDefinition(BeanDefinition original) {
		super(original);
	}


	@Override
	public String getParentName( ) {
		return null;
	}

	@Override
	public void setParentName(@Nullable String parentName) {
		if (parentName != null) {
			throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
		}
	}

	/**
	 * 注册由该bean definition修饰的目标definition。
	 */
	public void setDecoratedDefinition(@Nullable BeanDefinitionHolder decoratedDefinition) {
		this.decoratedDefinition = decoratedDefinition;
	}

	/**
	 * Return the target definition that is being decorated by this bean definition, if any.
	 */
	@Nullable
	public BeanDefinitionHolder getDecoratedDefinition( ) {
		return this.decoratedDefinition;
	}

	/**
	 * 指定{@link AnnotatedElement}defining 限定符，以代替目标类或工厂方法使用。
	 * {@link AnnotatedElement} 表示此VM中当前正在运行的程序的带注释元素。
	 *
	 * @see #setTargetType(ResolvableType)
	 * @see #getResolvedFactoryMethod()
	 * @since 4.3.3
	 */
	public void setQualifiedElement(@Nullable AnnotatedElement qualifiedElement) {
		this.qualifiedElement = qualifiedElement;
	}

	/**
	 * Return the {@link AnnotatedElement} defining qualifiers, if any.
	 * Otherwise, the factory method and target class will be checked.
	 *
	 * @since 4.3.3
	 */
	@Nullable
	public AnnotatedElement getQualifiedElement( ) {
		return this.qualifiedElement;
	}

	/**
	 * 如果事先知道，请指定此bean definition的包含泛型的目标类型。
	 *
	 * @since 4.3.3
	 */
	public void setTargetType(ResolvableType targetType) {
		this.targetType = targetType;
	}

	/**
	 * Specify the target type of this bean definition, if known in advance.
	 *
	 * @since 3.2.2
	 */
	public void setTargetType(@Nullable Class<?> targetType) {
		this.targetType = (targetType != null ? ResolvableType.forClass(targetType) : null);
	}

	/**
	 * Return the target type of this bean definition, if known
	 * (either specified in advance or resolved on first instantiation).
	 *
	 * @since 3.2.2
	 */
	@Nullable
	public Class<?> getTargetType( ) {
		if (this.resolvedTargetType != null) {
			return this.resolvedTargetType;
		}
		ResolvableType targetType = this.targetType;
		return (targetType != null ? targetType.resolve() : null);
	}

	/**
	 * Return a {@link ResolvableType} for this bean definition,
	 * either from runtime-cached type information or from configuration-time
	 * {@link #setTargetType(ResolvableType)} or {@link #setBeanClass(Class)},
	 * also considering resolved factory method definitions.
	 *
	 * @see #setTargetType(ResolvableType)
	 * @see #setBeanClass(Class)
	 * @see #setResolvedFactoryMethod(Method)
	 * @since 5.1
	 */
	@Override
	public ResolvableType getResolvableType( ) {
		ResolvableType targetType = this.targetType;
		if (targetType != null) {
			return targetType;
		}
		ResolvableType returnType = this.factoryMethodReturnType;
		if (returnType != null) {
			return returnType;
		}
		Method factoryMethod = this.factoryMethodToIntrospect;
		if (factoryMethod != null) {
			return ResolvableType.forMethodReturnType(factoryMethod);
		}
		return super.getResolvableType();
	}

	/**
	 * 确定用于默认构造的首选构造函数（如果有）。 如有必要，构造函数参数将自动装配。
	 *
	 * @return 一个或多个首选构造函数，如果没有，则为{@code null}（在这种情况下，将调用常规的无参数默认构造函数）
	 * @since 5.1
	 */
	@Nullable
	public Constructor<?>[] getPreferredConstructors( ) {
		return null;
	}

	/**
	 * 指定引用非重载方法的工厂方法名称。
	 *
	 * @param name 工厂方法名称  不允许重载
	 */
	public void setUniqueFactoryMethodName(String name) {
		Assert.hasText(name, "Factory method name must not be empty");
		setFactoryMethodName(name);
		this.isFactoryMethodUnique = true;
	}

	/**
	 * 指定引用重载方法的工厂方法名称。
	 *
	 * @param name 工厂方法名称  重载的
	 * @since 5.2
	 */
	public void setNonUniqueFactoryMethodName(String name) {
		Assert.hasText(name, "Factory method name must not be empty");
		setFactoryMethodName(name);
		this.isFactoryMethodUnique = false;
	}

	/**
	 * 检查给定的候选者是否是工厂方法。
	 */
	public boolean isFactoryMethod(Method candidate) {
		return candidate.getName().equals(getFactoryMethodName());
	}

	/**
	 * 为 bean definition设置一个已解析的Java方法作为工厂方法。
	 *
	 * @param method the resolved factory method, or {@code null} to reset it
	 * @since 5.2
	 */
	public void setResolvedFactoryMethod(@Nullable Method method) {
		this.factoryMethodToIntrospect = method;
	}

	/**
	 * Return the resolved factory method as a Java Method object, if available.
	 *
	 * @return the factory method, or {@code null} if not found or not resolved yet
	 */
	@Nullable
	public Method getResolvedFactoryMethod( ) {
		return this.factoryMethodToIntrospect;
	}

	public void registerExternallyManagedConfigMember(Member configMember) {
		synchronized (this.postProcessingLock) {
			if (this.externallyManagedConfigMembers == null) {
				this.externallyManagedConfigMembers = new HashSet<>(1);
			}
			this.externallyManagedConfigMembers.add(configMember);
		}
	}

	public boolean isExternallyManagedConfigMember(Member configMember) {
		synchronized (this.postProcessingLock) {
			return (this.externallyManagedConfigMembers != null &&
					this.externallyManagedConfigMembers.contains(configMember));
		}
	}

	public void registerExternallyManagedInitMethod(String initMethod) {
		synchronized (this.postProcessingLock) {
			if (this.externallyManagedInitMethods == null) {
				this.externallyManagedInitMethods = new HashSet<>(1);
			}
			this.externallyManagedInitMethods.add(initMethod);
		}
	}

	public boolean isExternallyManagedInitMethod(String initMethod) {
		synchronized (this.postProcessingLock) {
			return (this.externallyManagedInitMethods != null &&
					this.externallyManagedInitMethods.contains(initMethod));
		}
	}

	public void registerExternallyManagedDestroyMethod(String destroyMethod) {
		synchronized (this.postProcessingLock) {
			if (this.externallyManagedDestroyMethods == null) {
				this.externallyManagedDestroyMethods = new HashSet<>(1);
			}
			this.externallyManagedDestroyMethods.add(destroyMethod);
		}
	}

	public boolean isExternallyManagedDestroyMethod(String destroyMethod) {
		synchronized (this.postProcessingLock) {
			return (this.externallyManagedDestroyMethods != null &&
					this.externallyManagedDestroyMethods.contains(destroyMethod));
		}
	}


	@Override
	public RootBeanDefinition cloneBeanDefinition( ) {
		return new RootBeanDefinition(this);
	}

	@Override
	public boolean equals(@Nullable Object other) {
		return (this == other || (other instanceof RootBeanDefinition && super.equals(other)));
	}

	@Override
	public String toString( ) {
		return "Root bean: " + super.toString();
	}

}
